package com.hsu.hsurpc.server.tcp;

import cn.hutool.core.util.IdUtil;
import com.hsu.hsurpc.RpcApplication;
import com.hsu.hsurpc.model.RpcRequest;
import com.hsu.hsurpc.model.RpcResponse;
import com.hsu.hsurpc.model.ServiceMetaInfo;
import com.hsu.hsurpc.protocal.*;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.net.NetClient;
import io.vertx.core.net.NetSocket;

import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 * 基于 Vert.x 实现的 TCP 客户端
 * @Author Hsu琛君珩
 * @Date 2024-09-23 10:37
 * @Description
 * @Version: v1.0.0
 */
public class VertxTcpClient {

    /**
     * 发送 RPC 请求并接收响应。
     *
     * @param rpcRequest       要发送的 RPC 请求对象
     * @param serviceMetaInfo  服务提供者的元数据信息
     * @return RPC 响应对象
     * @throws InterruptedException 如果线程被中断
     * @throws ExecutionException   如果计算抛出异常
     */
    public static RpcResponse doRequest(RpcRequest rpcRequest, ServiceMetaInfo serviceMetaInfo) throws InterruptedException, ExecutionException {
        Vertx vertx = Vertx.vertx(); // 创建 Vert.x 实例
        NetClient netClient = vertx.createNetClient(); // 创建 NetClient 客户端实例
        CompletableFuture<RpcResponse> responseFuture = new CompletableFuture<>(); // 创建异步结果处理器
        // 连接到服务端
        netClient.connect(serviceMetaInfo.getServicePort(), serviceMetaInfo.getServiceHost(),
                result -> {
                    if (!result.succeeded()) {
                        // 如果连接失败，输出错误信息并返回
                        System.err.println("Failed to connect to TCP server");
                        return;
                    }
                    NetSocket socket = result.result();// 获取连接成功后的 socket
                    // 构建协议消息
                    ProtocolMessage<RpcRequest> protocolMessage = new ProtocolMessage<>();
                    ProtocolMessage.Header header = new ProtocolMessage.Header();
                    header.setMagic(ProtocolConstant.PROTOCOL_MAGIC); // 设置消息魔数
                    header.setVersion(ProtocolConstant.PROTOCOL_VERSION); // 设置协议版本
                    header.setSerializer((byte) ProtocolMessageSerializerEnum.getEnumByValue(RpcApplication.getRpcConfig().getSerializer()).getKey()); // 设置序列化器
                    header.setType((byte) ProtocolMessageTypeEnum.REQUEST.getKey()); // 设置消息类型为请求
                    header.setRequestId(IdUtil.getSnowflakeNextId()); // 设置唯一请求 ID
                    protocolMessage.setHeader(header); // 设置消息头
                    protocolMessage.setBody(rpcRequest); // 设置消息体
                    try {
                        // 编码请求消息
                        Buffer encodeBuffer = ProtocolMessageEncoder.encode(protocolMessage);
                        socket.write(encodeBuffer); // 发送编码后的消息
                    } catch (Exception e) {
                        throw new RuntimeException("协议消息编码错误");
                    }
                    // 使用 TcpBufferHandlerWrapper 处理接收到的响应
                    TcpBufferHandlerWrapper bufferHandlerWrapper = new TcpBufferHandlerWrapper(
                            buffer -> {
                                try {
                                    // 解码响应消息
                                    ProtocolMessage<RpcResponse> rpcResponseProtocolMessage =
                                            (ProtocolMessage<RpcResponse>) ProtocolMessageDecoder.decode(buffer);
                                    // 完成响应的 future
                                    responseFuture.complete(rpcResponseProtocolMessage.getBody());
                                } catch (IOException e) {
                                    throw new RuntimeException("协议消息解码错误");
                                }
                            }
                    );
                    socket.handler(bufferHandlerWrapper); // 设置 socket 的处理器为包装后的 handler
                });
        RpcResponse rpcResponse = responseFuture.get(); // 阻塞等待响应结果
        netClient.close(); // 关闭客户端连接
        return rpcResponse;
    }
}
